# cd /pubx/llvm-project/analyze_clang_by_gdb/; gdb -x TokenName_Print.gs    --args /pubx/llvm15-build/bin/clang    -c user_main.cpp -o user_main.o
# 大约十几分钟之后才会有打印输出(此时执行到了User.h)
# grep -i  expand TokenName_Print.log   #执行完后, 在日志中搜索 展开expand, 有如下函数. 即将 寻找宏展开处 ExpandMacro.gs
#2  0x0000555563154bfb in clang::Preprocessor::HandleMacroExpandedIdentifier (this=0x55556375bcf0, Identifier=..., M=...) at /pubx/llvm-project/clang/lib/Lex/PPMacroExpansion.cpp:477
#2  0x0000555563154bfb in clang::Preprocessor::HandleMacroExpandedIdentifier (this=0x55556375bcf0, Identifier=..., M=...) at /pubx/llvm-project/clang/lib/Lex/PPMacroExpansion.cpp:477
#1  0x00005555631551e3 in clang::Preprocessor::HandleMacroExpandedIdentifier (this=0x55556375bcf0, Identifier=..., M=...) at /pubx/llvm-project/clang/lib/Lex/PPMacroExpansion.cpp:582
#2  0x00005555631551f9 in clang::Preprocessor::HandleMacroExpandedIdentifier (this=0x55556375bcf0, Identifier=..., M=...) at /pubx/llvm-project/clang/lib/Lex/PPMacroExpansion.cpp:582
#2  0x0000555563154bfb in clang::Preprocessor::HandleMacroExpandedIdentifier (this=0x55556375bcf0, Identifier=..., M=...) at /pubx/llvm-project/clang/lib/Lex/PPMacroExpansion.cpp:477


#/pubx/llvm-project/clang/lib/Lex/PPMacroExpansion.cpp
# /// HandleMacroExpandedIdentifier - If an identifier token is read that is to be
# /// expanded as a macro, handle it and return the next token as 'Identifier'.
# bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
                                                 # const MacroDefinition &M) {
# //...
  # // Start expanding the macro.
  # EnterMacro(Identifier, ExpansionEnd, MI, Args); #第630行
  # return false;
# }

#执行: cd /pubx/llvm-project/analyze_clang_by_gdb/; gdb -x ExpandMacro.gs    --args /pubx/llvm15-build/bin/clang    -c user_main.cpp -o user_main.o

set logging file ExpandMacro.log
set logging on

set print pretty on
set pagination off

set follow-exec-mode new
set follow-fork-mode child

set breakpoint pending on

# 自定义gdb命令 create_cstr_with_len_then_print  $_srcCStr  $_copyLength  $_title:  复制来源字符串开头的给定长度字符串 并打印
source create_cstr_with_len_then_print.gs

#{找到CompilerInstance对象、找到SourceManager对象、在堆中分配bool对象 开始
#人工 从 Twine_union_Child_print.gs 中 应该去  函数 createPreprocessor 
break CompilerInstance.cpp:473
#断点1 clang::CompilerInstance::createPreprocessor ( ) at /pubx/llvm-project/clang/lib/Frontend/CompilerInstance.cpp:473
commands 1
	disable 1

	frame 2
	#2  0x000055555e12011f in clang::CompilerInstance::ExecuteAction (this=0x555563747760, Act=...) at /pubx/llvm-project/clang/lib/Frontend/CompilerInstance.cpp:1034
	set $ciPtr=this
	set $smPtr=& ( $ciPtr->getSourceManager() )

	frame 0
	#0  clang::CompilerInstance::createPreprocessor (this=0x555563747760, TUKind=clang::TU_Complete) at /pubx/llvm-project/clang/lib/Frontend/CompilerInstance.cpp:473
	set $boolPtr=(bool*)(malloc(sizeof(bool)))
#找到CompilerInstance对象、找到SourceManager对象、在堆中分配bool对象 结束}


	break clang::Preprocessor::cacheMacroExpandedTokens   if ($_fileNamCStr=$smPtr->getFilename( tokLexer->ExpandLocStart ).Data) != 0 && ( strcmp("./User.h",$_fileNamCStr)==0 || strcmp("./user_main.cpp",$_fileNamCStr)==0 )

# 2       breakpoint     keep y   0x00005555631589f6 in clang::Preprocessor::cacheMacroExpandedTokens(clang::TokenLexer* tokLexer, llvm::ArrayRef<clang::Token> tokens) at /pubx/llvm-project/clang/lib/Lex/PPMacroExpansion.cpp:1050
		#人工停在断点3处：  
			#参数 tokens 表示的是 该宏调用语句 展开后的单词序列;  
				# print tokens
				# tokens.Data[0...tokens.Length-1]   表示 该宏调用语句 展开后的单词序列: int gen_func_ ## mySum ( float  _arg1 ,  double  _arg2 ) 
				# tokens.Length : 11   表示 展开后的单词序列中有11个单词
			#参数 tokLexer:   
				#tokLexer->Macro 表示的是  该宏调用语句 的 原样 ,
				#tokLexer->Tokens[0... tokLexer->NumTokens-1 ] 表示的也是 该宏调用语句 展开后的单词序列
			#注意看 frame 1 :
			#1    in clang::TokenLexer::ExpandFunctionArguments () at /pubx/llvm-project/clang/lib/Lex/TokenLexer.cpp:605, 代码如下:
			# Tokens = PP.cacheMacroExpandedTokens(this, ResultToks); //ResultToks 即 该宏调用语句 展开后的单词序列.  (ResultToks名字很合理)
			

	commands 2
		silent
		# print $smPtr->getFilename( tokLexer->ExpandLocStart ).Data
		#
			#总结:

				#该宏调用语句 位于 : 从位置 tokLexer->ExpandLocStart 到位置 tokLexer->ExpandLocEnd
			set $macroCall_start__fileId_tkIdx= $smPtr->getDecomposedLoc(tokLexer->ExpandLocStart)
			set $macroCall_end__fileId_tkIdx= $smPtr->getDecomposedLoc(tokLexer->ExpandLocEnd)

			set $fileId=$macroCall_start__fileId_tkIdx.first
			#$macroCall_start__fileId_tkIdx.first 和 $macroCall_start__fileId_tkIdx.first 是一样的, 即 文件id一样, 都在同一个源代码文件中
			set $macroCall_start_tkIdx=$macroCall_start__fileId_tkIdx.second
			set $macroCall_end_tkIdx=$macroCall_end__fileId_tkIdx.second

			set $bufferData= $smPtr->getBufferData($fileId,$boolPtr)
			set $bufferDataCStr=$bufferData.Data

			#构造宏名字字符串, 打印, 释放
			create_cstr_with_len_then_print  $bufferDataCStr+$macroCall_start_tkIdx  $macroCall_end_tkIdx-($macroCall_start_tkIdx-1) "macroCallStmt:"

			#打印: macroCallStmt:func_define(mySum,INT,FLOAT,DOUBLE)


			#该宏调用语句 展开后单词序列: tokens.Data[0...tokens.Length-1] : TODO
			#循环遍历 该宏调用语句 展开后单词序列
				# 该宏调用语句 展开后单词序列:  是变量 各个 $_rTokICStrPtr 的concat,  这是TODO
			set $resultTokenArr=tokens.Data
			set $resultTokenCnt=tokens.Length
			set $_k=0
			set $_cnt=$resultTokenCnt

			while ($_k < $_cnt)
				set $_rTokIPtr=$resultTokenArr+$_k
				#即: set $_rTokIPtr=&(tokens.Data[$_k])
				set $_rTokIKind=$_rTokIPtr->Kind
				#即: set $_rTokIKind=tokens.Data[$_k].Kind
				set $_rTokINameCStr=$_rTokIPtr->getName()
				#即: set $_rTokINameCStr=tokens.Data[$_k].getName()
				
				set $_rTokICStrPtr=0
				if $_rTokIKind == clang::tok::identifier
					set $_rTokICStrPtr= $_rTokIPtr->getIdentifierInfo () ->Entry->getKey().Data
					#即: set $_rTokICStrPtr=tokens.Data[$_k].getIdentifierInfo () ->Entry->getKey().Data
				end
				#if结束

				if $_rTokIKind == clang::tok::hashhash || $_rTokIKind == clang::tok::comma || $_rTokIKind == clang::tok::l_paren || $_rTokIKind == clang::tok::r_paren
					set $_rTokICStrPtr= $_rTokINameCStr
				end
				#if结束
				
				if $_rTokIKind == clang::tok::kw_int || $_rTokIKind == clang::tok::kw_float || $_rTokIKind == clang::tok::kw_double
					set $_rTokICStrPtr= $_rTokINameCStr
				end
				#if结束
				
				
				printf "第%d个: kind数值 %d: Name %s",$_k,$_rTokIKind,$_rTokINameCStr
				if $_rTokICStrPtr != 0
					printf ": 展开值 %s\n", $_rTokICStrPtr
				else
					printf ": 展开值 TODO 没被本段代码匹配到\n"
				end
				#if结束

				
				set $_k=$_k+1
			end
			#循环结束

#打印:
# 第0个: kind数值 93: Name int: 展开值 int
# 第1个: kind数值 5: Name identifier: 展开值 gen_func_
# 第2个: kind数值 67: Name hashhash: 展开值 hashhash
# 第3个: kind数值 5: Name identifier: 展开值 mySum
# 第4个: kind数值 21: Name l_paren: 展开值 l_paren
# 第5个: kind数值 88: Name float: 展开值 float
# 第6个: kind数值 5: Name identifier: 展开值 _arg1
# 第7个: kind数值 65: Name comma: 展开值 comma
# 第8个: kind数值 84: Name double: 展开值 double
# 第9个: kind数值 5: Name identifier: 展开值 _arg2
# 第10个: kind数值 22: Name r_paren: 展开值 r_paren


			

			#打印当前位置部分代码
			# print $smPtr->getCharacterData($_tokenLocation,$boolPtr)
			
			#打印调用栈
			# bt
			
		
		#若想在User.h中感兴趣的宏处停下, 注释掉紧挨着的continue即可， 在停下后多次手工continue 即可到达想要的宏处
		# continue
		#断点2 停止后   不需要停下
	end
	#断点2处理结束

continue
#断点1 停止后 不需要停下
end
#断点1 处理结束


run

#因断点1 而停下
